﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace FileMonitor.Service.Tracking.Manager
{

    internal class TrackingComparer : IEqualityComparer<ITracking>
    {
        public bool Equals(ITracking x, ITracking y)
        {
            return x.TrackingName==y.TrackingName;
        }
    
        public int GetHashCode(ITracking obj)
        {
            return obj.TrackingName.GetHashCode();
        }
    }
    public class DefaultTrackingManager : ITrackingManager
    {

        private TrackingComparer _trackingComparer;
        private List<ITracking> _registerTrackingRouting;

        private Thread _workThreading;
        private EventWaitHandle _waitHandle;
        
        private Queue<TrackingTask> _taskQueue;
        private ITrackingTaskInvoker _taskInvoker;
      
        private object resgiterLocker = new object();
        private object _invokerLocker;


        public DefaultTrackingManager()
        {
            _registerTrackingRouting = new List<ITracking>();
            resgiterLocker = new object();
            _invokerLocker = new object();
            _waitHandle = new AutoResetEvent(false);
            _trackingComparer = new TrackingComparer();
            _taskQueue = new Queue<TrackingTask>();
            _taskInvoker = new DefaultTrackingTaskInvoker();
            _workThreading = new Thread(new ThreadStart(InvokeTask));
        }

        #region Private Methods
        private void InvokeTask()
        {
            while (true)
            {
                TrackingTask task = null;
                lock (_invokerLocker)
                {
                    if (this._taskQueue.Count > 0)
                    {
                        task = this._taskQueue.Dequeue();
                        if (task == null)
                        {
                            return;
                        }
                    }
                }
                if (task != null)
                {
                    ProcessTask(task);
                }
                else
                    _waitHandle.WaitOne();
            }
        }

        private void ProcessTask(TrackingTask task)
        {
            foreach (ITracking routing in this._registerTrackingRouting)
            {
                this._taskInvoker.InvokeTask(routing, task);
            }
        }
        #endregion

        #region Public Methods
        public void EnqueTask(TrackingTask trackingTask)
        {
            lock (_invokerLocker)
            {
                _taskQueue.Enqueue(trackingTask);
            }
            _waitHandle.Set();
        }

        public void RegisterTrackingRouting(ITracking trackingRouting)
        {
            if (!_registerTrackingRouting.Contains(trackingRouting, _trackingComparer))
            {
                lock (resgiterLocker)
                {
                    if (!_registerTrackingRouting.Contains(trackingRouting, _trackingComparer))
                    {
                        _registerTrackingRouting.Add(trackingRouting);
                        _registerTrackingRouting = _registerTrackingRouting.OrderBy(routing => routing.OrderNo).ToList();
                    }
                }
            }
        }

        public void StartTracking()
        {
            this._workThreading.Start();
        }
        public void StopTracking()
        {
            this.EnqueTask(null);
        }

        #endregion

    }
}
